/* eslint-disable no-use-before-define */
import { chain, many, matchTokenType, optional } from "../syntax-parser";
import { reserveKeys } from "./reserve-keys";

// ----------------------------------- Utils -----------------------------------

// TODO: https://github.com/antlr/grammars-v4/blob/master/mysql/MySqlParser.g4#L1963
// 字段类型
const simpleDataType = () => {
  return chain([
    [
      "INT",
      "SMALLINT",
      "TINYINT",
      "BIGINT",
      "BIT",
      "BOOLEAN",
      "FLOAT",
      "DOUBLE",
      "NUMERIC",
      "DATE",
      "TIME",
      "DATETIME",
      "TIMESTAMP",
      "TEXT",
      "BLOB",
      "ENUM",
      "SET",
      "JSON",
      "STRING",
    ],
    chain(
      ["CHAR", "VARCHAR", "NCHAR", "NVARCHAR", "BINARY", "VARBINARY"],
      optional("(", numberSym, ")")
    ),
    chain("DECIMAL", optional("(", numberSym, ",", numberSym, ")")),
  ])();
};
const structItem = () => {
  return chain(wordSym, ":", dataType, optional("COMMENT", stringSym))();
};

const complexDataType = () => {
  return chain([
    chain("ARRAY", "<", dataType, ">"),
    chain("MAP", "<", simpleDataType, ",", dataType, ">"),
    chain("STRUCT", "<", structItem, many(",", structItem), ">"),
  ])();
};
export const dataType = () => {
  return chain([simpleDataType, complexDataType])();
};

export const setValue = () => {
  return chain(wordSym, "=", [stringSym, numberSym])();
};

export const setValueList = () => {
  return chain(setValue, many(",", setValue))();
};

// ----------------------------------- others -----------------------------------

export const udfLocationSym = () => {
  return chain([matchTokenType("cursor"), matchTokenType("udflocation")])(
    (ast) => {
      return ast[0];
    }
  );
};

export const wordSym = () => {
  return chain([matchTokenType("cursor"), matchTokenType("word")])((ast) => {
    return ast[0];
  });
};

export const stringSym = () => {
  return chain(matchTokenType("string"))((ast) => {
    return ast[0];
  });
};

export const numberSym = () => {
  return chain(matchTokenType("number"))((ast) => {
    return ast[0];
  });
};

export const stringOrWord = () => {
  return chain([wordSym, stringSym])((ast) => {
    return ast[0];
  });
};

export const tableNameSym = () => {
  return chain([wordSym, stringSym, numberSym])((ast) => {
    return ast[0];
  });
};

export const stringOrWordOrNumber = () => {
  return chain([wordSym, stringSym, numberChain])((ast) => {
    return ast[0];
  });
};

export const numberChain = () => {
  return chain(optional(["-", "+"]), numberSym)();
};

export const logicalOperator = () => {
  return chain(["and", "&&", "xor", "or", "||"])((ast) => {
    return ast[0];
  });
};

export const normalOperator = () => {
  return chain(["&&", "||"])((ast) => {
    return ast[0];
  });
};

export const comparisonOperator = () => {
  return chain(["=", ">", "<", "<=", ">=", "<>", "!=", "<=>"])((ast) => {
    return ast[0];
  });
};

export const notOperator = () => {
  return chain(["not", "!"])((ast) => {
    return ast[0];
  });
};

export const selectSpec = () => {
  return chain([
    "all",
    "distinct",
    "distinctrow",
    "high_priority",
    "straight_join",
    "sql_small_result",
    "sql_big_result",
    "sql_buffer_result",
    "sql_cache",
    "sql_no_cache",
    "sql_calc_found_rows",
  ])((ast) => {
    return ast[0];
  });
};
